/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.dp1.pucp.Modelo.Algoritmos;


import java.util.ArrayList;
import java.util.Random;

/**
 *
 * @author Rodrigo
 */
public class Grasp {
    
   public static float ALPHA = 0.815f;//menos estable un poquito mayor (mas generalizado)
   public static int ITERACIONES = 10000;
   public static double COSTOOPERACION = 50;
   
   
   
   
   public void ordenarGalletas(ArrayList<Galleta> arregloGalletas){
    Galleta aux = new Galleta();
    for (int i=0; i< arregloGalletas.size() -1 ; i++){
        for(int j=i+1; j< arregloGalletas.size(); j++){
            Galleta a = arregloGalletas.get(i);
            Galleta b = arregloGalletas.get(j);
           if( a.calcularUtilidad() < b.calcularUtilidad()){
               aux = b;
               arregloGalletas.set(j, a);
               arregloGalletas.set(i, aux);
           }
         }
      }
    }
   
    public boolean verificarDemandaCubierta(int[] arr, int numpedido){
       
       for(int i=0; i< arr.length ;i++){
         if(arr[i] < numpedido)  return false;
       }
       return true;
       
   }

    
    public void calculaEficiencias(ArrayList<EmpleadoAlgoritmo> aux, TipoGalleta tipo){
      for(int i=0;i < aux.size(); i++){
              for(int j=0; j < tipo.getMaquinasProceso().size();j++){
              int id_tipomaquina = tipo.getMaquinasProceso().get(j);
              int prod = aux.get(i).getProduccion()[id_tipomaquina -1];
              int merm = aux.get(i).getMermas()[id_tipomaquina -1];
              double porc= tipo.getPorcentajesValor().get(j);
              double e = prod*tipo.getPrecio()*porc - merm*tipo.getCosto()*porc;
              aux.get(i).getEficiencia()[id_tipomaquina-1] =e;
             
              }      
      }
  }
  
   public EmpleadoAlgoritmo obtenerSeleccionadoRCL(ArrayList<EmpleadoAlgoritmo> aux, int id_tipomaquina, double alpha){
       
       //ACA ORDENAREMOS LA LISTA SEGUN EL TIPO DE MAQINA 
       
     EmpleadoAlgoritmo empaux = new EmpleadoAlgoritmo();
       
      for (int i=0; i< aux.size() -1 ; i++){//ordenamos la lista del mejor al peor
        for(int j=i+1; j< aux.size(); j++){
            EmpleadoAlgoritmo a = aux.get(i);
            EmpleadoAlgoritmo b = aux.get(j);
           if( a.getEficiencia()[id_tipomaquina-1] < b.getEficiencia()[id_tipomaquina-1]){
               empaux = b;
               aux.set(j, a);
               aux.set(i, empaux);
           }
        }
      }
        
       EmpleadoAlgoritmo mejor = aux.get(0);
       double beta = mejor.getEficiencia()[id_tipomaquina-1];
       EmpleadoAlgoritmo peor = aux.get(aux.size() - 1);
       double tao = peor.getEficiencia()[id_tipomaquina-1];
       int i;
   
       for( i=0;i< aux.size();i++){//calculamos el rango RCL
           
           if(aux.get(i).getEficiencia()[id_tipomaquina-1] >= beta - alpha*(beta - tao) && aux.get(i).getEficiencia()[id_tipomaquina-1]<= beta );//lleno a lista con los candidatos que entran en el rango
           else break;
       }
       Random random = new Random();
       
       return   aux.remove(random.nextInt(i));
           
   }
   
   
    
    public ArrayList<Galleta> copiargall(ArrayList<Galleta> array){
       ArrayList<Galleta> arr = new ArrayList() ;
       for(int i =0;i<array.size();i++){
           Galleta b = array.get(i);
        Galleta a = new Galleta(b.getIdgalleta(),b.getTipogalleta(),b.getNumGalletasPedidas(),b.getInv_ini_proc(), b.getDemanda_maq_pedida(),b.getDemanda_maq_cubierta(), b.getInv_nuevo());
        arr.add(a);
       }
       return arr;
    }
    
     public ArrayList<EmpleadoAlgoritmo> copiaremp(ArrayList<EmpleadoAlgoritmo> array){
       ArrayList<EmpleadoAlgoritmo> arr = new ArrayList() ;
       for(int i =0;i<array.size();i++){
           EmpleadoAlgoritmo b = array.get(i);
        EmpleadoAlgoritmo a = new EmpleadoAlgoritmo(b.getIdempleado(),b.getProduccion(),b.getMermas(), b.getTurno());
        arr.add(a);
       }
       return arr;
    }
       public Solucion graspConstruccion(ArrayList<EmpleadoAlgoritmo> empleados, ArrayList<Galleta> arregloGalletas, Maquinas maquinas, int iteraciones , double alpha){
        
        Solucion sol = new Solucion();
        //sol.setTurno(turno);
        ArrayList<EmpleadoAlgoritmo> empleadosaux= new ArrayList();
        ArrayList<Galleta> galletaaux = new ArrayList();
       
        EmpleadoAlgoritmo seleccionado;
        ordenarGalletas(arregloGalletas);
        int id=0;
        
        for(int i=0;i<iteraciones;i++){//bucle del grasp
            Solucion solucion = new Solucion(); 
            empleadosaux = copiaremp(empleados);
            galletaaux= copiargall(arregloGalletas);
           //**
            Maquinas maqaux = new Maquinas(maquinas);
            MaquinaA maq = new MaquinaA();
            //**
            int tam = galletaaux.size();
            for(int j=0;j<tam ;j++){//arreglo para las 3 galletas
                Galleta galleta = galletaaux.get(j);
                calculaEficiencias(empleadosaux,galleta.getTipogalleta());
                int tam2 = galleta.getTipogalleta().getMaquinasProceso().size();
               // int[] arr_demanda = galleta.getDemanda_maq_cubierta();     
                //creo un arreglo de tamaño igual a la cantidad de maquinas que requiere una determinada galleta    
                int numpedido = galleta.getNumGalletasPedidas();
              // int[] numpedido = galletaaux.get(j).getdemanda_maq_pedida();
               // while(!verificarDemandaCubierta(arr_demanda, numpedido) && empleadosaux.size() > 0 && !maqaux.maquinasDisponibles() ){//mientras no haya cubierto la demanda en todas las maqinas, haya empleados y haya maquinas disponibles
                 while(galleta.verificaDemCub() && empleadosaux.size()>0 && galleta.maquinasDisponibles(maqaux)) {     
                    
                    for(int k=0;k < tam2 ;k++){//por cada tipo de maqina de la galleta j
                             id=0;
                            seleccionado = null;
                            int id_tipomaquina = galletaaux.get(j).getTipogalleta().getMaquinasProceso().get(k);
                            if(empleadosaux.isEmpty() || maqaux.maquinanoDisponible(id_tipomaquina)) {
                            
                        }//verificamos si aun hay empleados y maquinas disponibles 
                            else{                                                   
                          //  if(arr_demanda[k] < numpedido) {//asigno para ese tipo de maquina si aun falta cubrir 
                              if(galleta.verifNODemCubProc(k)){
                                seleccionado = obtenerSeleccionadoRCL(empleadosaux, id_tipomaquina, alpha);//selecciono el candidato
                               //arr_demanda[k] = arr_demanda[k] + seleccionado.getCapacidad()[id_tipomaquina-1];
                               galleta.actualizaDemCub(k, seleccionado.getCapacidad()[id_tipomaquina-1]);
                              
                               maq =  maqaux.getMaqAsig(id_tipomaquina);
                               maq.setEstado(1);   
                               seleccionado.setMaquina(maq.getIdmaquina());//averiguar porq puse la siguiente condicion
                               
                               seleccionado.setGalletaAsignada(galletaaux.get(j)); 
                               seleccionado.setTipoMaquinaAsignada(id_tipomaquina);
                               solucion.getAsignados().add(seleccionado);
                               solucion.getMaquinas().add(maq);
                               solucion.calcularObjetivo(seleccionado, COSTOOPERACION);    
                          }
                         }
                     } 
                }
                 //galletaaux.get(j).setDemanda_maq_cubierta(arr_demanda);
                //galletaaux.get(j).calcularDemandacubierta(arr_demanda);//por ahora estamos definiendo que la demada cubierta de un tipo de galleta sea la demanda cubierta en la ultima maquina del proceso
                galleta.calDemCubV2();
            }
            solucion.setGalletas(galletaaux);
            if ( sol.getFuncionObjetivo()==0){ sol = solucion;
                
            }
            else if(sol.getFuncionObjetivo() < solucion.getFuncionObjetivo()){ sol = solucion;}

        }
        
        return sol;
    }
     
      public Solucion graspConstruccion2(ArrayList<EmpleadoAlgoritmo> empleados, ArrayList<Galleta> arregloGalletas, Maquinas maquinas, int iteraciones , double alpha, int turno){
        
        Solucion sol = new Solucion();
      //  sol.setTurno(turno);
        ArrayList<EmpleadoAlgoritmo> empleadosaux= new ArrayList();
        ArrayList<Galleta> galletaaux = new ArrayList();
       
        EmpleadoAlgoritmo seleccionado;
        ordenarGalletas(arregloGalletas);
        int id=0;
        int itera =1;
        for(int i=0;i<iteraciones;i++){//bucle del grasp
            Solucion solucion = new Solucion(); 
            empleadosaux = copiaremp(empleados);
            galletaaux= copiargall(arregloGalletas);
           //**ordenar aqui dentro mejor
            Maquinas maqaux = new Maquinas(maquinas);
            MaquinaA maq = new MaquinaA();
            //**
            int tam = galletaaux.size();
            for(int j=0;j<tam ;j++){//arreglo para las 3 galletas
                Galleta galleta = galletaaux.get(j);
                calculaEficiencias(empleadosaux,galleta.getTipogalleta());
                int tam2 = galleta.getTipogalleta().getMaquinasProceso().size();
                    //creo un arreglo de tamaño igual a la cantidad de maquinas que requiere una determinada galleta    
                int numpedido = galleta.getNumGalletasPedidas();
                    // while(!verificarDemandaCubierta(arr_demanda, numpedido) && empleadosaux.size() > 0 && !maqaux.maquinasDisponibles() ){//mientras no haya cubierto la demanda en todas las maqinas, haya empleados y haya maquinas disponibles
                 while(galleta.verificaDemCub() && empleadosaux.size()>0){// && galleta.maquinasDisponibles(maqaux)) {     
                    int id_tipomaquina = 4;
                    for(int k=0;k < tam2 ;k++){//por cada tipo de maqina de la galleta j
                             id=0;
                            seleccionado = null;
                             id_tipomaquina = galletaaux.get(j).getTipogalleta().getMaquinasProceso().get(k);
                            if(empleadosaux.isEmpty() || maqaux.maquinanoDisponible(id_tipomaquina)) {
                            
                        }//verificamos si aun hay empleados y maquinas disponibles 
                            else{                                                   
                                 if(galleta.verifNODemCubProc(k)){
                                seleccionado = obtenerSeleccionadoRCL(empleadosaux, id_tipomaquina, alpha);//selecciono el candidato
                                  galleta.actualizaDemCub(k, seleccionado.getCapacidad()[id_tipomaquina-1]);
                              
                               maq =  maqaux.getMaqAsig(id_tipomaquina);
                               maq.setEstado(1);   
                               seleccionado.setMaquina(maq.getIdmaquina());//averiguar porq puse la siguiente condicion
                               
                               seleccionado.setGalletaAsignada(galletaaux.get(j)); 
                               seleccionado.setTipoMaquinaAsignada(id_tipomaquina);
                               solucion.getAsignados().add(seleccionado);
                               solucion.getMaquinas().add(maq);
                               solucion.calcularObjetivo(seleccionado, COSTOOPERACION);    
                          }
                         }
                    
                     } 
                       if(maqaux.maquinanoDisponible(id_tipomaquina)) break;
                }
                   galleta.calDemCubV2();
            }
            solucion.setGalletas(galletaaux);
            if ( sol.getFuncionObjetivo()==0){ sol = solucion;
                
            }
            else if(sol.getFuncionObjetivo() < solucion.getFuncionObjetivo()){ sol = solucion;}

        }
        sol.setTurno(turno);
        return sol;
    }
      
     
    
 public Solucion grasp_run(ArrayList<EmpleadoAlgoritmo> empleados, ArrayList<Galleta> galletas, Maquinas maquinas){
    return this.graspConstruccion(empleados, galletas,maquinas, ITERACIONES, ALPHA);
 }
}
